package com.itheima.servcie;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.itheima.bean.CodeBean;
import com.itheima.dbservice.FocusUserServiceApi;
import com.itheima.dbservice.UserInfoServiceApi;
import com.itheima.exception.CommonException;
import com.itheima.mongoservice.CommentsServiceApi;
import com.itheima.mongoservice.SmallVideosServiceApi;
import com.itheima.pojo.FocusUser;
import com.itheima.pojo.UserInfo;
import com.itheima.pojo.mongo.Comment;
import com.itheima.pojo.mongo.Movement;
import com.itheima.pojo.mongo.Video;
import com.itheima.template.OssTemplate;
import com.itheima.vo.mongo.AllVo;
import com.itheima.vo.mongo.CommentsVo;
import com.itheima.vo.mongo.VideoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.awt.print.Pageable;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class SmallVideosService {
    @DubboReference
    private SmallVideosServiceApi smallVideosServiceApi;
    @DubboReference
    private UserInfoServiceApi userInfoServiceApi;
    @DubboReference
    private CommentsServiceApi commentsServiceApi;
    @DubboReference
    private FocusUserServiceApi focusUserServiceApi;
    @Autowired
    private CommentsService commentsService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private FastFileStorageClient fastFileStorageClient;
    @Autowired
    private FdfsWebServer fdfsWebServer;

    public AllVo getSmallVideosList(Integer page, Integer pagesize) {
        //获取当前用户id下的推荐视频
        Long uid = Convert.toLong(redisTemplate.opsForValue().get(CodeBean.ID));
        List<Integer> vids = Convert.toList(Integer.class, redisTemplate.opsForValue().get(CodeBean.VIDEOS_RECOMMEND + uid));
        //判断推荐视频是否看完并将对应小视频展示
        if (vids.size()/5 < page){
            List<Video> videos = smallVideosServiceApi.getSmallVideosList((page-vids.size()/5), pagesize);
            //封装返回值
            return getAllVo(page, pagesize, videos);
        }
        //存入集合
        List<Video> videos = new ArrayList<>();
        for (Integer vid : vids) {
            //查询对应的视频
            Video video = smallVideosServiceApi.getByVid(vid);
            videos.add(video);
        }
        //封装并返回
        return getAllVo((page - 1) * pagesize, pagesize, videos);
    }

    /**
     * 封装返回值
     * @param page
     * @param pagesize
     * @param videos
     * @return
     */
    private AllVo getAllVo(Integer page, Integer pagesize, List<Video> videos) {
        List<VideoVo> videoVoList = new ArrayList<>();
        //查询视频作者信息
        for (Video video : videos) {
            UserInfo userInfo = userInfoServiceApi.getUserInfoById(video.getUserId());
            VideoVo videoVo = VideoVo.init(userInfo, video);
            videoVoList.add(videoVo);
        }
        AllVo allVo = new AllVo();
        allVo.setPagesize(pagesize);
        allVo.setPage(page);
        allVo.setPages(videos.size()/ pagesize);
        allVo.setCounts(videos.size());
        allVo.setItems(videoVoList.toArray());
        return allVo;
    }

    public void upLoadVideo(MultipartFile videoThumbnail, MultipartFile videoFile) {
        try {
            //获取当前登陆者id
            Long uid = Convert.toLong(redisTemplate.opsForValue().get(CodeBean.ID));
            //将缩略图上传至阿里云
            String fileUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());
            //将视频文件上传至fdfs
            String filename = videoFile.getOriginalFilename();
            //获取文件后缀名
            String sufix = filename.substring(filename.lastIndexOf(".") + 1);
            StorePath path = fastFileStorageClient.uploadFile(videoFile.getInputStream(), videoFile.getSize(), sufix, null);
            //获取路径
            String videoUrl = fdfsWebServer.getWebServerUrl() + path.getFullPath();
            //封装并存入集合中
            Video video = new Video();
            video.setCreated(System.currentTimeMillis());
            video.setUserId(uid);
            video.setText("这玩意前端没给，给个默认的得了");
            video.setPicUrl(fileUrl);
            video.setVideoUrl(videoUrl);
            video.setLikeCount(0);
            video.setCommentCount(0);
            video.setLoveCount(0);
            //存入集合
            smallVideosServiceApi.upLoadVideo(video);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void like(String id) {
        //判断是否已点赞
        String uid = stringRedisTemplate.opsForValue().get(CodeBean.ID);
        boolean res = commentsServiceApi.isExist(new ObjectId(id), uid, 1);
        if (res){
            throw new CommonException("已点赞，不能再点了哦");
        }
        //检查是否点赞
        if (stringRedisTemplate.opsForHash().hasKey(CodeBean.VIDEO_LIKE_HASHKEY + Convert.toStr(id), CodeBean.VIDEO_LIKE_HASHKEY + uid)){
            throw new CommonException("已点赞，不能再点了哦");
        }
        //1为点赞
        saveComment(new ObjectId(id), 1, null);
        //redis存储已点赞动态信息
        stringRedisTemplate.opsForHash().put(CodeBean.VIDEO_LIKE_HASHKEY + Convert.toStr(id),
                CodeBean.VIDEO_LIKE_HASHKEY + uid, "1");
        //查询喜欢数并返回
//        Movement movementInfo = movementServiceApi.getMovementInfo(Convert.toStr(id));
        //更新表中数据
//        movementInfo.setLikeCount(movementInfo.getLikeCount() + 1);
//        movementServiceApi.updateMovement(movementInfo);
    }

    //封装Comment
    private void saveComment(ObjectId id, Integer type, String content){
        Comment comment = new Comment();
        comment.setPublishId(id);
        //获取当前动态发布人id
        Video video = smallVideosServiceApi.getVideoById(Convert.toStr(id));
        comment.setUserId(video.getUserId());
        //获取评论者id
        String uid = stringRedisTemplate.opsForValue().get(CodeBean.ID);
        //封装
        comment.setCommentType(type);
        //封装评论(1点赞  2评论)
        comment.setContent(type == 2 ? content : null);
        comment.setCreated(System.currentTimeMillis());
        comment.setLikeCount(0);
        comment.setPublishUserId(Convert.toLong(uid));
        commentsServiceApi.comment(comment);
        //更新movement里的喜欢和评论参数
        addMovementComment(type, video);
    }

    //更新movement里的喜欢和评论参数(点赞,新增)
    private void addMovementComment(Integer type, Video video) {
        Video videoInfo = new Video();
        videoInfo.setId(video.getId());
        if (ObjectUtil.equal(type, 1)) {
            videoInfo.setLikeCount(video.getLikeCount() != null ? video.getLikeCount() + 1 : 1);
        }else {
            //保存原始数据，直接存null更新会覆盖原有数据
            if (video.getLikeCount() != null)
                videoInfo.setLikeCount(video.getLikeCount());
        }
        if (ObjectUtil.equal(type, 3)) {
            videoInfo.setLoveCount(video.getLoveCount() != null ? videoInfo.getLoveCount() + 1 : 1);
        }else {
            //保存原始数据，直接存null更新会覆盖原有数据
            if (video.getLoveCount() != null)
                videoInfo.setLoveCount(video.getLoveCount());
        }
        if (ObjectUtil.equal(type, 2)) {
            videoInfo.setCommentCount(video.getCommentCount() != null ? video.getCommentCount() + 1 : 1);
        }else {
            //保存原始数据，直接存null更新会覆盖原有数据
            if (video.getCommentCount() != null)
                videoInfo.setCommentCount(video.getCommentCount());
        }
        //更新到movement
        smallVideosServiceApi.updateVideo(videoInfo);
    }

    //更新movement里的喜欢和评论参数(取消,减少)
    private void deleteMovementComment(Integer type, Video video) {
        Video videoInfo = new Video();
        videoInfo.setId(video.getId());
        if (ObjectUtil.equal(type, 1)) {
            videoInfo.setLikeCount(video.getLikeCount() != 1 ? video.getLikeCount() - 1 : 0);
        }else {
            //保存原始数据，直接存null更新会覆盖原有数据
            if (video.getLikeCount() != null)
                videoInfo.setLikeCount(video.getLikeCount());
        }
        if (ObjectUtil.equal(type, 3)) {
            videoInfo.setLoveCount(video.getLoveCount() != 1 ? videoInfo.getLoveCount() - 1 : 0);
        }else {
            //保存原始数据，直接存null更新会覆盖原有数据
            if (video.getLoveCount() != null)
                videoInfo.setLoveCount(video.getLoveCount());
        }
        if (ObjectUtil.equal(type, 2)) {
            videoInfo.setCommentCount(video.getCommentCount() != 1 ? video.getCommentCount() - 1 : 0);
        }else {
            //保存原始数据，直接存null更新会覆盖原有数据
            if (video.getCommentCount() != null)
                videoInfo.setCommentCount(video.getCommentCount());
        }
        //更新到movement
        smallVideosServiceApi.updateVideo(videoInfo);
    }

    public void dislike(String id) {
        //取出
        Video videoInfo = smallVideosServiceApi.getVideoById(id);
        //判断动态是否已点赞
        String uid = stringRedisTemplate.opsForValue().get(CodeBean.ID);
        boolean res = commentsServiceApi.isExist(new ObjectId(id), uid, 1);
        if (!res){
            throw new CommonException("未点赞，无法取消");
        }
        //删除数据库点赞数据
        commentsServiceApi.deleteComment(new ObjectId(id), uid, 1);
        //redis删除已点赞动态信息
        stringRedisTemplate.opsForHash().delete(CodeBean.VIDEO_LIKE_HASHKEY + Convert.toStr(id),
                CodeBean.VIDEO_LIKE_HASHKEY + uid);
        deleteMovementComment(1, videoInfo);
    }

    public void userFocus(Long uid) {
        Long myId = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        if (ObjectUtil.equal(uid, myId)){
            throw new CommonException("您不能关注自己");
        }
        //检查是否已关注
        FocusUser focusUser = focusUserServiceApi.getByIdAndUid(myId, uid);
        //分情况
        if (ObjectUtil.isNull(focusUser)){
            //存入
            FocusUser focusUserInfo = new FocusUser();
            focusUserInfo.setUserId(myId);
            focusUserInfo.setFocusId(uid);
            focusUserInfo.setCreated(new Date());
            focusUserServiceApi.save(focusUserInfo);
        }else {
            throw new CommonException("您已关注");
        }
    }

    public void userUnFocus(Long uid) {
        Long myId = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //检查是否已关注
        FocusUser focusUser = focusUserServiceApi.getByIdAndUid(myId, uid);
        //分情况
        if (ObjectUtil.isNotNull(focusUser)){
            //删除关注信息
            focusUserServiceApi.delete(myId, uid);
        }else {
            throw new CommonException("您未关注");
        }
    }

    public AllVo comments(Integer page, Integer pagesize, String id) {
        //获取对应动态的评论
        List<Comment> comments = commentsServiceApi.getMovementComments(page, pagesize, id);

        //填充集合
        List<CommentsVo> list = new ArrayList<>();
        for (Comment comment : comments) {
            //获取对应评论的用户信息
            UserInfo commenterInfo = userInfoServiceApi.getUserInfoById(comment.getPublishUserId());
            CommentsVo commentsVo = new CommentsVo();
            //评论(2为是否评论)
            if (comment.getCommentType() == 2) {
                //封装CommentsVo
                commentsVo.setId(comment.getId().toHexString());
                commentsVo.setAvatar(commenterInfo.getAvatar());
                commentsVo.setNickname(commenterInfo.getNickname());
                commentsVo.setContent(comment.getContent());
                commentsVo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(comment.getCreated())));
                commentsVo.setLikeCount(comment.getLikeCount() != null ? comment.getLikeCount() : 0);
            }
            //是否点赞(1为点赞)
            if (comment.getCommentType() == 1){
                commentsVo.setHasLiked(1);
            }
            list.add(commentsVo);
        }
        AllVo allVo = new AllVo();
        allVo.setPage(page);
        allVo.setPagesize(pagesize);
        allVo.setPages(comments.size()/pagesize+1);
        allVo.setCounts(comments.size());
        allVo.setItems(list.toArray());
        return allVo;
    }

    public void pushComments(String id, Map<String, String> map) {
        Long uid = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //评论内容
        String comment = map.get("comment");
        //检查用户被冻结范围
        log.info(CodeBean.FREEZE_USER + uid);
        String map1 = Convert.toStr(stringRedisTemplate.opsForValue().get(CodeBean.FREEZE_USER + uid));
        Map freezeMap = JSONUtil.toBean(map1, Map.class);
        //检查是否有该用户
        if (freezeMap.size() != 0){
            //检查用户被冻结范围，1为冻结登录，2为冻结发言，3为冻结发布动态
            Integer freezingRange = Convert.toInt(freezeMap.get("freezingRange"));
            if (ObjectUtil.equal(2, freezingRange)){
                throw new CommonException("您已被禁言");
            }
        }
        //2为评论
        saveComment(new ObjectId(id), 2, comment);
    }

    public void commentLike(ObjectId id) {
        commentsService.commentLike(id);
    }

    public void commentDislike(ObjectId id) {
        commentsService.commentDislike(id);
    }
}
